package XMLScene;

import Tracer.RTColor;
import Tracer.RTHitpointObjMap;
import Tracer.RTRay;
import Tracer.RTVector;

/**
 * Modal class of plane object
 * 
 * @author forrest lorraine eagle
 */
public class RTPlane implements RTIObject {
	/**
	 * normal vector of plane
	 */
	private RTVector pNormal;

	/**
	 * distance from (0,0,0) to plane
	 */
	private double pDistance;
	/**
	 * surface of plane, black by default
	 */
	private RTSurface pSurface;

	/**
	 * Constructor using a normal vector
	 * 
	 * @param normal
	 * @param distance
	 */
	public RTPlane(final RTVector normal, final double distance) {
		pDistance = distance;
		pNormal = new RTVector(normal);
		pSurface = new RTSurface(RTColor.BLACK);
	}

	/**
	 * Constructor using a normal vector and a point vector
	 * 
	 * @param normal
	 * @param point
	 */
	public RTPlane(final RTVector normal, final RTVector point) {
		pNormal = new RTVector(normal);
		pDistance = RTVector.dotProductVectors(point, pNormal);
		pSurface = new RTSurface(RTColor.BLACK);
	}

	/**
	 * Getter of normal vector
	 * 
	 * @return the normal of plane
	 */
	public final RTVector getNormal() {
		return this.pNormal;
	}

	/**
	 * Getter of distance member
	 * 
	 * @return the distance from (0,0,0) to the plane
	 */
	public final double getDistance() {
		return pDistance;
	}

	/**
	 * Setter of distance member
	 * 
	 * @param d
	 */
	public final void setDistance(final double d) {
		pDistance = d;
	}

	/**
	 * Getter of surface
	 * 
	 * @return the surface of plane
	 */
	public final RTSurface getSurface() {
		return pSurface;
	}

	/**
	 * Setter of surface
	 * 
	 * @param s
	 *            the surface
	 */
	public final void setSurface(final RTSurface s) {
		pSurface = s;
	}

	/**
	 * detect the hit points for plane object
	 * 
	 * @param ray
	 *            the ray to detect a hit point with
	 * @param hitPointObjSingleMap
	 *            the original variable to store detected result, to avoid
	 *            frequently new
	 * @return the detected result
	 */
	public final RTHitpointObjMap objectHitDetect(final RTRay ray,
			final RTHitpointObjMap hitPointObjSingleMap) {
		// the distance from (0,0,0) to the panel
		double distanceOP = pDistance;
		// the cos value for angle of plane normal and ray
		double angleND = RTVector
				.dotProductVectors(pNormal, ray.getDirection());
		// construct a plane R through R0 and parallel with plane, the
		// distance between R and Plane
		double distanceRP = distanceOP
				- RTVector.dotProductVectors(pNormal, ray.getStartPoint());

		if (angleND > 0) {
			// angle < 90 go up
			if (distanceRP >= 0) {
				// below the panel
				// will hit, since below and go up
				// distance between ray origin and intersection
				double distanceOH = distanceRP / angleND;
				// calculate normal vector

				hitPointObjSingleMap.setHitPoint(RTVector.sumVectors(ray
						.getStartPoint(), RTVector.multipleVectors(ray
						.getDirection(), distanceOH)));
				hitPointObjSingleMap.setHitObject(this);
				hitPointObjSingleMap.setHitNormal(RTVector
						.reverseVector(pNormal));
			} else {
				return null;
			}
		} else if (angleND < 0) {
			// go down
			if (distanceRP <= 0) {
				// above the panel
				// distance between ray origin and intersection
				double distanceOH = distanceRP / angleND;

				hitPointObjSingleMap.setHitPoint(RTVector.sumVectors(ray
						.getStartPoint(), RTVector.multipleVectors(ray
						.getDirection(), distanceOH)));
				hitPointObjSingleMap.setHitObject(this);
				// calculate normal vector
				hitPointObjSingleMap.setHitNormal(pNormal);
			} else {
				return null;
			}
		} else { // parallel , not hit
			return null;
		}
		return hitPointObjSingleMap;
	}

	/**
	 * to get the original color of plane object
	 * 
	 * @param validHitPointObjMap
	 *            the valid hit points
	 * @return the original color of plane object
	 */
	public final RTColor calOriginColor(
			final RTHitpointObjMap validHitPointObjMap) {
		if (pSurface.getPigment().getColor() != null) {
			return pSurface.getPigment().getColor();
		}
		return null;
	}

}
